package com.hunttown.common.sharding.client;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.client.SqlMapSession;
import com.hunttown.common.sharding.client.annotation.ISharding;
import com.hunttown.common.sharding.client.annotation.Sharding;
import com.hunttown.common.sharding.client.datasource.ShardingDataSources;
import com.hunttown.common.sharding.client.exception.UnknownDataAccessException;
import com.hunttown.common.sharding.client.util.BeanPropertyAccessUtil;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.jdbc.support.JdbcAccessor;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.util.Assert;

public class SimpleShardJdbcTemplate extends JdbcAccessor implements InitializingBean {
    private SqlMapClient sqlMapClient;

    public SimpleShardJdbcTemplate() {
    }

    public Object queryForObject(final String statementName, final Object parameterObj) throws DataAccessException {
        SqlMapClientCallback callback = new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForObject(statementName, parameterObj);
            }
        };
        return this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterObj), callback);
    }

    public List queryForList(final String statementName, final Object parameterObj) throws DataAccessException {
        SqlMapClientCallback callback = new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForList(statementName, parameterObj);
            }
        };
        return (List) this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterObj), callback);
    }

    public Object insert(final String statementName, final Object parameterObj) throws DataAccessException {
        SqlMapClientCallback callback = new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.insert(statementName, parameterObj);
            }
        };
        return this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterObj), callback);
    }

    public Object insertByBatch(final String statementName, final List parameterList) throws DataAccessException {
        if (parameterList != null && parameterList.size() != 0) {
            SqlMapClientCallback callback = new SqlMapClientCallback() {
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    executor.startBatch();
                    Iterator i$ = parameterList.iterator();

                    while (i$.hasNext()) {
                        Object parameterObj = i$.next();
                        executor.insert(statementName, parameterObj);
                    }

                    executor.executeBatch();
                    return parameterList.size();
                }
            };
            return this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterList), callback);
        } else {
            return Integer.valueOf(-1);
        }
    }

    public int update(final String statementName, final Object parameterObject) throws DataAccessException {
        SqlMapClientCallback callback = new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.update(statementName, parameterObject);
            }
        };
        Integer rowsAffected = (Integer) this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterObject), callback);
        return rowsAffected == null ? 0 : rowsAffected.intValue();
    }

    public int updateByBatch(final String statementName, final List parameterList) throws DataAccessException {
        if (parameterList != null && parameterList.size() != 0) {
            SqlMapClientCallback callback = new SqlMapClientCallback() {
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    executor.startBatch();
                    Iterator i$ = parameterList.iterator();

                    while (i$.hasNext()) {
                        Object parameterObj = i$.next();
                        executor.update(statementName, parameterObj);
                    }

                    executor.executeBatch();
                    return parameterList.size();
                }
            };
            Integer rowsAffected = (Integer) this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterList), callback);
            return rowsAffected == null ? 0 : rowsAffected.intValue();
        } else {
            return -1;
        }
    }

    public int delete(final String statementName, final Object parameterObject) throws DataAccessException {
        SqlMapClientCallback callback = new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.delete(statementName, parameterObject);
            }
        };
        Integer rowsAffected = (Integer) this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterObject), callback);
        return rowsAffected == null ? 0 : rowsAffected.intValue();
    }

    public int deleteByBatch(final String statementName, final List parameterList) throws DataAccessException {
        if (parameterList != null && parameterList.size() != 0) {
            SqlMapClientCallback callback = new SqlMapClientCallback() {
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    executor.startBatch();
                    Iterator i$ = parameterList.iterator();

                    while (i$.hasNext()) {
                        Object parameterObj = i$.next();
                        executor.delete(statementName, parameterObj);
                    }

                    executor.executeBatch();
                    return parameterList.size();
                }
            };
            Integer rowsAffected = (Integer) this.executeWithObjectResult(this.getRoutedSingleDataSource(parameterList), callback);
            return rowsAffected == null ? 0 : rowsAffected.intValue();
        } else {
            return -1;
        }
    }

    protected Object executeWithObjectResult(DataSource dataSource, SqlMapClientCallback callback) throws DataAccessException {
        Assert.notNull(dataSource, "None DataSource is specified!");
        Assert.notNull(callback, "None SqlMapClientCallback is specified!");
        Assert.notNull(this.getSqlMapClient(), "None SqlMapClient is specified!");
        SqlMapSession session = this.getSqlMapClient().openSession();

        Object t;
        try {
            Connection springCon = null;
            boolean isTransactionAware = dataSource instanceof TransactionAwareDataSourceProxy;

            try {
                springCon = isTransactionAware ? dataSource.getConnection() : DataSourceUtils.getConnection(dataSource);
                session.setUserConnection(springCon);
            } catch (SQLException var29) {
                throw new CannotGetJdbcConnectionException("Could not Get Jdbc Connection!", var29);
            }

            try {
                t = callback.doInSqlMapClient(session);
            } catch (SQLException var26) {
                t = var26;
                throw (new SQLErrorCodeSQLExceptionTranslator()).translate("SqlMapClient operation", (String) null, var26);
            } catch (Throwable var27) {
                t = var27;
                throw new UnknownDataAccessException("Unknown exception occurs on processing data access!", var27);
            } finally {
                try {
                    if (springCon != null) {
                        if (isTransactionAware) {
                            springCon.close();
                        } else {
                            DataSourceUtils.releaseConnection(springCon, dataSource);
                        }
                    }
                } catch (Throwable var25) {
                    var25.printStackTrace();
                }

            }
        } finally {
            session.close();
        }

        return t;
    }

    protected DataSource getRoutedSingleDataSource(Object parameterObj) {
        String dataSourceName = null;

        try {
            if (parameterObj instanceof List) {
                List<Object> shardList = (List) parameterObj;
                if (shardList != null && shardList.size() > 0) {
                    Object shardObj = shardList.get(0);
                    if (shardObj instanceof Sharding || shardObj instanceof ISharding) {
                        dataSourceName = (String) BeanPropertyAccessUtil.getPropertyValue("dataSourceName", shardObj);
                    }
                }
            } else if (parameterObj instanceof Map) {
                Map<String, Object> shardMap = (Map) parameterObj;
                if (shardMap.containsKey("dataSourceName")) {
                    dataSourceName = (String) shardMap.get("dataSourceName");
                }
            } else if (parameterObj instanceof Sharding || parameterObj instanceof ISharding) {
                dataSourceName = (String) BeanPropertyAccessUtil.getPropertyValue("dataSourceName", parameterObj);
            }
        } catch (Throwable var5) {
            var5.printStackTrace();
        }

        Assert.notNull(dataSourceName, "get DataSourceName error!");
        return dataSourceName != null ? this.getDataSourceByName(dataSourceName) : null;
    }

    public void afterPropertiesSet() {
        if (this.getSqlMapClient() == null) {
            throw new IllegalArgumentException("Property 'sqlMapClient' is required");
        } else {
            if (!this.isLazyInit()) {
                this.getExceptionTranslator();
            }

        }
    }

    public SqlMapClient getSqlMapClient() {
        return this.sqlMapClient;
    }

    public void setSqlMapClient(SqlMapClient sqlMapClient) {
        this.sqlMapClient = sqlMapClient;
    }

    public DataSource getDataSourceByName(String dataSourceName) {
        return ShardingDataSources.getInstance().getDataSource(dataSourceName);
    }
}
